﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
using WcfMail.Interface;
using WcfMail;
using WcfMail.Common;

namespace Hisuntech.SystemFramework.Net.Mail
{
    public class ReciveMailDate
    {
        public string MailUserName;
        /// <summary>
        /// 最早的（上次检查）邮件时间
        /// </summary>
        public DateTime LastDate =new DateTime (1900,1,1);
        /// <summary>
        /// 最近的邮件时间
        /// </summary>
        public DateTime FirstDate = new DateTime(1900, 1, 1);

        //private bool isEachChecked = false;//是否已经遍历过所有邮件
        private  DateTime currMaxDate = new DateTime(1900, 1, 1);

        public ReciveMailDate(string userNamme)
        {
            this.MailUserName = userNamme;
        }

        /// <summary>
        /// 根据当前邮件日期，判断是否是新邮件，如果是，则应该接收处理该邮件，否则，可以中断本次邮件消息循环
        /// </summary>
        /// <param name="currMailDate"></param>
        /// <param name="messageId"></param>
        /// <returns></returns>
        public bool IsNewMail(DateTime currMailDate,int messageId)
        {
            if (currMailDate.AddDays(1) < DateTime.Now)
                return false;//1 天之前的邮件不再处理，认为是旧邮件

            if (currMailDate > this.currMaxDate )
            {
                this.currMaxDate = currMailDate.AddHours(-1);//1小数内的邮件都认为是新邮件
                if (currMailDate > this.LastDate && messageId == 0)
                {
                    this.LastDate = this.currMaxDate;
                }
                return true;
               
            }
            else
            {
               
                if (currMailDate > this.LastDate && messageId > 0)
                {
                    
                    return true;
                }
                else
                {
                    this.LastDate = this.currMaxDate;
                    return false;
                }
            }
        }

       

    }

    /// <summary>
    /// 邮件操作抽象类
    /// </summary>
    public abstract class Emails :  ITransfer
    {
        /// <summary>
        /// 默认等待反馈的时间为4分钟
        /// </summary>
        const int DEFAULT_CALLBACK_TIMEOUT = 200;
        protected  int CHECK_MAIL_MAX_COUNT = 50;

        /// <summary>
        /// 等待反馈邮件的超时时间（不计算接收邮件过程的时间），如果不指定，将使用默认的时间，单位 秒
        /// </summary>
        public int CallbackTimeout = 0;

        public delegate void SendCallBack(); 

        #region 字段
        /// <summary>
        /// 上一次接收邮件的时间
        /// </summary>
        private  Dictionary<string, ReciveMailDate> dicteciveDate = new Dictionary<string, ReciveMailDate>();
        /// <summary>
        /// 要匹配的标题头,只有符合该标题的邮件才会接收到邮件消息列表
        /// </summary>
        public string MatchingTitle = "";
        /// <summary>
        /// 是否在接收邮件后（存入邮件消息列表的邮件）就立即将邮件从服务器删除，默认否
        /// </summary>
        public bool ReceiveAndDelete = false;

        static List<ISysMsg> _cumsg = null;

        private MailServerInfo _Pop3_Server=null;
        private MailServerInfo _Smtp_Server=null;

        public string AttachmentPath = "./MailAttachment";
       

        #endregion

        #region 属性
       
       

        /// <summary>
        /// 上次操作的错误消息
        /// </summary>
        public string ErrorMessage { get; protected set; }
        /// <summary>
        /// 当前处理的邮件消息对象对象
        /// </summary>
        public MailMessageInfo CurrentMailInfo { get; set; }

       
        /// <summary>
        /// （邮件）消息队列,所有实例对象都将使用一个共同的静态消息队列
        /// <remarks>
        /// 由于多个实例对象有可能不加区别的收取邮件到本地，把本该当前实例对象处理的邮件接收了，
        /// 所以必须把邮件放到一个静态列表中来处理。
        /// </remarks>
        /// </summary>
        public virtual List<ISysMsg> MessageQueue
        {
            get
            {
                if (null == _cumsg)
                    _cumsg = new List<ISysMsg>();
                return _cumsg;
            }
            set
            {
                _cumsg = value;
            }
        }

        public virtual MailServerInfo POP3_Server
        {
            get
            {
                if (this._Pop3_Server == null)
                {
                    this._Pop3_Server = MailConfig.GetConfig(MailServerType.POP3);
                }
                return this._Pop3_Server;
            }
            set
            {
                this._Pop3_Server = value;
            }
        }

        public virtual MailServerInfo SMTP_Server
        {
            get
            {
                if (this._Smtp_Server == null)
                {
                    this._Smtp_Server = MailConfig.GetConfig(MailServerType.SMTP);
                }
                return this._Smtp_Server;
            }
            set
            {
                this._Smtp_Server = value;
            }
        }
 
        #endregion

        #region 事件相关
        /// <summary>
        /// 接收邮件中
        /// </summary>
        public event EventHandler<SystemMessageEventArgs> ReceivingHandler;
        /// <summary>
        /// 接收邮件完成
        /// </summary>
        public event EventHandler<SystemMessageEventArgs> ReceivedHandler;

        /// <summary>
        /// 接收反馈邮件超时事件，如果超过指定的连续等待时间都还没有收到全部的反馈邮件，将触发该事件
        /// </summary>
        public event EventHandler<SystemMessageEventArgs> OnCallBackTimeOut;

        /// <summary>
        /// 接收到反馈邮件
        /// </summary>
        public event EventHandler<FeedbackMessageEventArgs> OnFeedbacked;

        protected void Receiving(ISysMsg message)
        {
            if (this.ReceivingHandler != null)
                this.ReceivingHandler(this, new SystemMessageEventArgs(message));
        }

        protected void Received(ISysMsg message)
        {
            if (this.ReceivedHandler != null)
                this.ReceivedHandler(this, new SystemMessageEventArgs(message));
        }

        #endregion

        private int checkCount = 0;

        protected void ReceiveInit()
        {
            checkCount = 0;
        }

       

        #region ITransfer 成员
        /// <summary>
        /// 发送邮件，如果不成功，请检查错误消息。
        /// </summary>
        /// <param name="message">邮件消息</param>
        /// <returns>是否成功</returns>
        public abstract bool Send(ISysMsg message);

        /// <summary>
        /// 开启等待反馈的线程，如果没有线程在运行，则开启成功，反之则不成功
        /// </summary>
        /// <returns></returns>
        public bool StartWaitingCallBankThread()
        {
            if (!isWaitingCallBack)
            {
                //this.IsCallbackTimeOut = false;
                //开启线程，检查
                System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(WaiteCallBack));
                t.Name = "反馈邮件线程";
                t.Start();
                return true;
            }
            return false;
        }
       
        /// <summary>
        /// 发送邮件，并指定邮件发送成功且对方处理后收到反馈的回调方法
        /// </summary>
        /// <param name="message"></param>
        /// <param name="callBack"></param>
        /// <returns></returns>
        public bool Send(ISysMsg message, bool needCallBack)
        {
            if (this.Send(message))
            {
                string subject = message.MsgSubject;
                if (subject.EndsWith("_ZIP"))
                    subject = subject.Substring(0, subject.Length - 4);

                if (!CallbackMailTitle.Contains(subject))
                    CallbackMailTitle.Add(subject);

                if (needCallBack)
                {
                    StartWaitingCallBankThread();
                }
                else
                {
                    this.FeedbackAllDone = true;//如果不处理回调使得程序可以退出
                }
                return true;
            }
            return false;
        }

       

        /// <summary>
        /// 接收邮件，如果成功，所有邮件将存入消息队列；如果不成功，请检查错误消息。
        /// </summary>
        /// <param name="message">接收邮件需要附加的操作消息，一般不需要指定</param>
        /// <returns>是否成功</returns>
        public virtual bool Receive(ISysMsg message)
        {
            if (!Directory.Exists(this.AttachmentPath))
            {
                Directory.CreateDirectory(this.AttachmentPath);
            }
            if (message == null)
            {
                this.ErrorMessage = "参数 message 为空。";
                return false;
            }
            
            return this.Receive(message, false, 0);
        }
        

        #endregion

        #region 反馈邮件

        private List<string> _returnReceipt = null;
        /// <summary>
        /// 回执列表（元素为当前邮件的标题）
        /// </summary>
        protected List<string> ReturnReceipt
        {
            get
            {
                if (_returnReceipt == null)
                    _returnReceipt = new List<string>();
                return _returnReceipt;
            }
            set { _returnReceipt = value; }
        }


        List<string> callBackTitle =null;

        /// <summary>
        /// 当前需要反馈的邮件标题，如果没有完全反馈成功，可以检查该属性。
        /// </summary>
        public List<string> CallbackMailTitle
        {
            get {
                if (callBackTitle == null)
                    callBackTitle = new List<string>();
                return callBackTitle;
            }
        }

        private bool isWaitingCallBack = false;
        /// <summary>
        /// 是否正在等待反馈的线程中
        /// </summary>
        public bool IsWaitingCallBack
        {
            get { return IsCallbackTimeOut; }
        }

        /// <summary>
        /// 本伦反馈已经全部完成
        /// </summary>
        public bool FeedbackAllDone { get; private set; }

        /// <summary>
        /// 是否发生了反馈超时事件
        /// </summary>
        public bool IsCallbackTimeOut { get; private set; }
        /// <summary>
        /// 检查反馈信息
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        private FeedbackMessage parseFeedbackMessage(string content)
        {
            IConvert convert = Converter.CreateInstance();
            FeedbackMessage fdMsg = convert.ConvertToObject<FeedbackMessage>(content);
            return fdMsg;
        }

        /// <summary>
        /// 不断的检查回信标记，等待反馈结果，直到处理完所有的待反馈信息
        /// </summary>
        private  void WaiteCallBack()
        {
            if (isWaitingCallBack) return;//确保只有一个线程在处理反馈信息

            FeedbackAllDone = false;
            IsCallbackTimeOut = false;
            isWaitingCallBack = true;

            if (CallbackTimeout == 0)
                CallbackTimeout = DEFAULT_CALLBACK_TIMEOUT;

            this.MatchingTitle = SystemConst.FEEDBACK_MAIL_TITLE_FLAG;
            SystemMessage msg = new SystemMessage();
            int currWateTime = 0;
            this.ReceiveAndDelete = true;

            while (callBackTitle.Count > 0)
            {
                //还需要考虑超时机制
                if (Receive(msg))
                {
                    if (this.MessageQueue.Count > 0)
                    {
                        //this.MessageQueue 在多个线程中，不能在这里枚举
                        ISysMsg[] currMessages = this.MessageQueue.ToArray();
                        foreach (ISysMsg message in currMessages)
                        {
                            string machedTitle = null;
                            this.UnZipContent(message, true);

                            foreach (string item in this.CallbackMailTitle.ToArray())
                            {
                                if (message.MsgSubject == SystemConst.FEEDBACK_MAIL_TITLE_FLAG + item)
                                {
                                    this.CallbackMailTitle.Remove(item);
                                    this.MessageQueue.Remove(message);

                                    if (this.OnFeedbacked != null)
                                    {
                                        FeedbackMessage feedbackMsg = parseFeedbackMessage(message.MsgContent);
                                        this.OnFeedbacked(this, new FeedbackMessageEventArgs(feedbackMsg));
                                        machedTitle = item;
                                        message.MsgType = null;//添加移除标记
                                    }
                                }
                            }
                        }//end for
                        //this.RemoveMessages();
                      
                    }

                    if(this.CallbackMailTitle.Count ==0)
                        currWateTime = 0;
                    else
                        currWateTime++;

                    //等待反馈超时，退出
                    if (currWateTime > this.CallbackTimeout)
                    {
                        this.IsCallbackTimeOut = true;
                        if (this.OnCallBackTimeOut != null)
                        {
                            string content = "以下邮件还没有收到反馈信息：\r\n";
                            foreach (string subject in callBackTitle)
                                content += subject + ";\r\n";

                            SystemMessage message = new SystemMessage();
                            message.MsgSubject = "接收反馈邮件超时";
                            message.MsgContent = content;
                            message.MsgType = "Feedback";

                            this.OnCallBackTimeOut(this, new SystemMessageEventArgs(message));
                        }
                        break;
                    }
                }
                System.Threading.Thread.Sleep(2000);//间隔2秒再收信
               
            }
            isWaitingCallBack = false;//检查结束标记
            FeedbackAllDone = true;
        }

        #endregion

        /// <summary>
        /// 删除收件箱中的邮件(删除前会把收件箱中的邮件放入邮件消息队列）
        /// </summary>
        /// <param name="isAll">是否删除全部邮件，否则，只删除当前邮件</param>
        /// <returns></returns>
        public virtual bool DeleteInboxMail(bool isAll)
        {
            if ((this.CurrentMailInfo != null) && !string.IsNullOrEmpty(this.POP3_Server.MailServer))
            {
                if (isAll)
                {
                    this.MessageQueue.Clear();
                    return this.Receive(this.CurrentMailInfo, true, 0);
                }
                return this.Receive(this.CurrentMailInfo, false, this.CurrentMailInfo.MessageID);
            }
            return false;
        }

        /// <summary>
        /// 接收邮件抽象方法
        /// </summary>
        /// <param name="message">邮件服务器信息</param>
        /// <param name="delMail">接收完成以后是否全部删除服务器上面的邮件</param>
        /// <param name="delMsgID">如果不全部删除，指定要删除的邮件序号（从1开始）</param>
        /// <returns>操作是否成功</returns>
        public abstract  bool Receive(ISysMsg message, bool delMail, int delMsgID);

       

        /// <summary>
        /// 从队列中移除无效的（使用过的）消息
        /// </summary>
        public virtual void RemoveMessages()
        {
            //if(_cumsg != null)
            //    _cumsg.RemoveAll(p => p.MsgType == null);
        }


        /// <summary>
        /// 检查指定用户的邮箱最近的邮件是否是新邮件
        /// </summary>
        /// <param name="currMailDate">当前邮件的时间</param>
        /// <param name="mailUser">指定的用户</param>
        ///  <param name="messageId">消息编号</param>
        /// <returns>如果是，则应该继续接收，否则可以直接等待下次的新邮件</returns>
        protected bool IsNewMail(DateTime currMailDate, string mailUser, int messageId)
        {
            if (!dicteciveDate.ContainsKey(mailUser))
            {
                dicteciveDate.Add(mailUser, new ReciveMailDate(mailUser));
            }
            checkCount++;
            int processCount = messageId;
            if (checkCount >= CHECK_MAIL_MAX_COUNT)
                processCount = 0;
            return dicteciveDate[mailUser].IsNewMail(currMailDate, processCount); 
        }

        #region 压缩邮件
        /// <summary>
        /// 对邮件消息正文进行编码（需要压缩的话请直接调用ZipClass）,message.MsgContent 必须是（二进制）8位编码的字符串
        /// </summary>
        /// <param name="message"></param>
        public virtual void ZipContent(ISysMsg message)
        {
            //由于有些邮件系统的限制，必须加以处理才可以发送
            if (!string.IsNullOrEmpty(message.MsgContent) && message.MsgContent.Length > 50)
            {
                message.MsgSubject = message.MsgSubject + "_ZIP";
                //下面一行代码测试压缩
                message.MsgContent = ZipClass.ZipString(message.MsgContent);
              
                message.MsgContent = AddCrlf(message.MsgContent, 200);
            }

        }

       
        /// <summary>
        ///  对邮件消息正文进行编码,并指定消息正文是否是8位编码的字符串，如果不是，将转换成8位编码字符串。
        /// </summary>
        /// <param name="message"></param>
        /// <param name="bit8String"></param>
        public virtual void ZipContent(ISysMsg message,bool bit8String)
        {
            if (bit8String)
                message.MsgContent = WcfMail.Common.Converter.To8BitString(message.MsgContent);
            ZipContent(message);
        }
        /// <summary>
        /// 解出缩邮件消息编码（需要解压的话请直接调用ZipClass）
        /// </summary>
        /// <param name="message"></param>
        public virtual void UnZipContent(ISysMsg message)
        {
            if (message.MsgSubject.EndsWith("_ZIP"))
            {
                message.MsgSubject = message.MsgSubject.Substring(0, message.MsgSubject.Length - 4);
                string strTemp = RemoveCrlf(message.MsgContent);
                //下面的一行代码是测试解压缩
                message.MsgContent = ZipClass.UnzipString(strTemp);
                //message.MsgContent = strTemp;
            }
        }

        /// <summary>
        /// 解码邮件消息，如果消息正文是8位编码的，将还原成UTF-8格式的字符串
        /// </summary>
        /// <param name="message">邮件消息</param>
        /// <param name="bit8String">正文是否是8位字符编码</param>
        public virtual void UnZipContent(ISysMsg message, bool bit8String)
        {
            UnZipContent(message);
            if (bit8String)
                message.MsgContent = WcfMail.Common.Converter.ToUtf8String(message.MsgContent);
        }


        /// <summary>
        /// 将字符串中的每个字符转换成它对应的内码的16进制，并按照指定的字数换行。
        /// 采用这种方式能够避免邮件内容被过滤，导致发送邮件失败。
        /// 注：字符串中不能有中文字符
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="size">需要添加换行的字符数</param>
        /// <returns>转换后的字符串</returns>
        public static string AddCrlf(string source, int size)
        {
            System.Text.StringBuilder sb = new StringBuilder(1024);
            int start = 0;

            int length = source.Length;
            //int count = 0;

            while (start < length)
            {
                if (start + size > length)
                    size = length - start;
                                char[] chars = source.Substring(start, size).ToCharArray();
                bool f = false;
                //count = 0;
                foreach (char c in chars)
                {
                    //将字符转换成16进制的字符串，不能有中文字符
                    Int16 i = Convert.ToInt16(c);//
                    if (i < 16)
                        sb.Append("0" + i.ToString("x"));
                    else
                        sb.Append(i.ToString("x"));

                    if (f)
                        sb.Append(",");
                    f = !f;
                    //count++;
                    //if (count >= 3)
                    //{
                    //    sb.Append(",");
                    //    count = 0;
                    //}
                }

                sb.Append("$\r\n");

                start = start + size;


            }
            return sb.ToString();
        }

        /// <summary>
        /// 删除字符串中的换行符，并将16进制字符串转换成ＡＳＣＩＩ字符
        /// </summary>
        /// <param name="source">AddCrlf　转换后的字符串</param>
        /// <returns>AddCrlf　结果反转后的原始字符串</returns>
        private string RemoveCrlf(string source)
        {
            System.Text.StringBuilder sb = new StringBuilder();
            string[] arrCrlf = source.Split(new string[] { "$" }, StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < arrCrlf.Length; i++)
            {
                string str = arrCrlf[i].Replace("\r\n",""); 
                int start = 0;
                int length = str.Length;
                //取2组数字,3组数字无法发出？非常奇怪，还是用2组数字可靠。
                while (start < length)
                {
                    string str1 = str.Substring(start, 2);
                    sb.Append((char)Int16.Parse(str1, System.Globalization.NumberStyles.AllowHexSpecifier));

                    if (start + 4 > length)
                        break;

                    string str2 = str.Substring(start + 2, 2);
                    sb.Append((char)Int16.Parse(str2, System.Globalization.NumberStyles.AllowHexSpecifier));

                    //if (start + 6 > length)
                    //    break;
                    //string str3 = str.Substring(start + 4, 2);
                    //sb.Append((char)Int16.Parse(str3, System.Globalization.NumberStyles.AllowHexSpecifier));

                    //start = start + 7;
                    start = start + 5;
                }
            }

            return sb.ToString();
        }

        #endregion


        #region 临时写文件,不再使用

        public bool WriteMail(string p_path, string p_str)
        {
            if (!System.IO.File.Exists(p_path))
            {
                System.IO.FileStream f = System.IO.File.Create(p_path);
                f.Close();
            }
            try
            {
                System.IO.StreamWriter f2 = new System.IO.StreamWriter(p_path, false, System.Text.Encoding.GetEncoding("utf-8"));
                f2.WriteLine(p_str);
                f2.Close();
                f2.Dispose();
            }
            catch { return false; }
            return true;
        }


        //public string ReciveMail(string FileName)
        //{
        //    //DirectoryInfo dir = new DirectoryInfo("");
        //    string mailContent = string.Empty;
        //    if (File.Exists(FileName))
        //    {
        //        StreamReader objReader = new StreamReader(FileName);
        //        mailContent = objReader.ReadToEnd();
        //        objReader.Close();      
 
               
        //    }

        //    return mailContent;

        //}

        //public ArrayList GetAllFiles(DirectoryInfo directory)
        //{
        //    ArrayList arr = new ArrayList();
        //    if (directory.Exists)
        //    {
        //        foreach (FileInfo info in directory.GetFiles())
        //        {
        //            if (info.Extension == ".txt")
        //                arr.Add(info.FullName.ToString());
        //        }

        //        foreach (DirectoryInfo info in directory.GetDirectories())
        //        {
        //            GetAllFiles(info);
        //        }
        //    }
        //    return arr;

        //}

        #endregion
    }

    
}
